﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using TicketSeller;

namespace FlightSearchServer
{
    class SearchService : ISearchService
    {
        public FlightRoutes search( string source, string destination, string date)
        {
            ServersCollection serversList = ServersManager.Instance.getServersCopy();
            ServersCollection usedServers = new ServersCollection();
            FlightRoutes results = new FlightRoutes( );
            Console.WriteLine( "Flight from {0} to {1} on {2}", source, destination, date);

            foreach (SearchServer server in serversList)
            {
                if (server.Failed || usedServers.Contains( server))
                    continue;
                string key1 = String.Format("{0}&{1}", server.Name, server.Alliance);
                string key2 = String.Format("&{0}&{1}&{2}&", source, destination, date);
                FlightRoutes cachedResults = LocalClientCache.Instance.getEntry( key1, key2);
                if (cachedResults != null)
                {
                    foreach (var x in cachedResults)
                        results.Add(x);
                    foreach (var x in server.HasReplicationOf)
                    {
                        usedServers.Add(x);
                    }
                    usedServers.Add(server);
                    Console.WriteLine( "Cache used search \"{0} to {1} on {2}\" on server {3}, alliance {4}, ", source, destination, date, server.Name, server.Alliance);
                    continue;
                }
                // send request to server and mark all 
                // servers which keep replication on current
                // in order to avoid asking them
                EndpointAddress endpoint = new EndpointAddress(new Uri(server.Endpoint));
                using (TicketsFinderServiceClient proxy = new TicketsFinderServiceClient(new BasicHttpBinding(), endpoint))
                {
                    Console.WriteLine("Going to call server : {0} of alliance {1}.", server.Name, server.Alliance);
                    //proxy.Endpoint.Behaviors.Add();
                    // Looking for direct flights
                    try
                    {
                        TicketsCollection tickets = proxy.search(source, destination, date);
                        // Now we need to discover indirect flights
                        TicketsCollection ticketsFrom = proxy.searchFrom(source, date);
                        TicketsCollection ticketsTo = proxy.searchTo(destination, date);
                        foreach (Ticket ticket in tickets)
                        {
                            results.Add(new Route(ticket));
                        }

                        // Add to previous results also indirect flights
                        foreach (var x in (from t1 in ticketsFrom
                                           join t2 in ticketsTo on t1.destination equals t2.source
                                           where t1.date == date && t1.source == source
                                                 && t2.date == date && t2.destination == destination
                                           select new Route(t1, t2)).ToList())
                        {
                            results.Add(x);
                        }
                        // Got results for all replication as well
                        foreach (var x in server.HasReplicationOf)
                        {
                            usedServers.Add(x);
                        }
                    }
                    catch (Exception e)
                    {
                        ServersManager.Instance.markAsFailed(server);
                        Console.WriteLine(e.Message);
                        GlobalResultsCache.Instance.invalidateCache();
                    }
                    finally
                    {
                        usedServers.Add(server);
                    }
                }
            }
            return results;
        }
    }
}
